package test;


import java.io.*;
import java.util.*;

public class forwardChange {
    ArrayList<fibLine> fl=new ArrayList<>();
    ArrayList<fibLine> flNotAll=new ArrayList<>();
    ArrayList<fibLine> flRest=new ArrayList<>();
    ArrayList<fibLine> flChange=new ArrayList<>();
    private static final String OUTPUT_PATH="config/i2Test/";
    String rest="apRest";
    String change="apChange";
    String preChange="apChangePre";
    ArrayList<String> nextInsert=new ArrayList<>();
    ArrayList<String> nextChangePort=new ArrayList<>();
    ArrayList<String> nextDel=new ArrayList<>();
    ArrayList<Integer> seed=new ArrayList<>();
    HashMap<String,Integer> apLength=new HashMap<>();
    int length=0;
    int portTime=1;



    public static void main(String[] args) throws IOException {

        //初始第一次划分文件
        String[] s = {"atla", "chic", "hous", "kans", "losa", "newy32aoa", "salt"};
        String[] cT = {"changePort", "del", "insert"};     //顺序执行使用
        forwardChange fwf = new forwardChange();
        for(String a:s) {
            fwf.fwdChangeI2(a + "ap", 1);
        }
    }

    public forwardChange(){};

    //每次change一条fwd rule，change类型和相应的文件都是随机的，此时没有随机种子记录
    public ArrayList<String> forwardChangeTestOneNoSeed(){
        ArrayList<String> s=new ArrayList<>();
        String changeType="  "; //本次执行的类型
        ArrayList<String> type=new ArrayList<>();


       // type.add("insert");
        type.add("changePort");
        if(nextInsert.size()>0){
            type.add("insert");
        }else
        {
            if(nextDel.size()>0)
            type.add("del");  //插完再进行删除
        }


        int i;
        int k=getRandom(0,type.size()-1);  //文件变化的类型

        if(type.get(k).equals("insert")) {

            if(nextInsert.size()==1){
                i = 0;
            }else{
                i = getRandom(0,nextInsert.size()-1);   //确定变化的文件
            }
            ArrayList<String> ni = new ArrayList<>(nextInsert);
            s.add(ni.get(i));
            changeType="insert";
            insertFwdOne(ni.get(i));
            //insertOne(ni.get(i));   //插入的基本都会改变最终结果 debug
        }else{
            if(type.get(k).equals("changePort")){

                i = getRandom(0,nextChangePort.size()-1);

                s.add(nextChangePort.get(i));

                readForwardFile(OUTPUT_PATH, nextChangePort.get(i), change);
                if(fl.size()<(apLength.get(nextChangePort.get(i))*0.98)&&fl.size()%10<5&&nextInsert.contains(nextChangePort.get(i))){
                    changeType="insert";
                    insertFwdOne(nextChangePort.get(i));
                }else {
                    changeFwdPortOne(nextChangePort.get(i));
                    changeType = "changePort";
                }

            }else
            {
                if(nextDel.size()==nextChangePort.size()&&type.get(k).equals("del")) {
                    i = getRandom(0,nextDel.size() - 1);

                    s.add(nextDel.get(i));

                    readForwardFile(OUTPUT_PATH, nextDel.get(i), change);
                    if(fl.size()<(apLength.get(nextDel.get(i))*0.98)&&fl.size()%10<5&&nextInsert.contains(nextDel.get(i))){
                        changeType="insert";
                        insertFwdOne(nextDel.get(i));
                    }else {
                        changeType="del";
                        delFwdOne(nextDel.get(i));
                    }

                }
            }
        }
        s.add(changeType);
        HashSet<fibLine> fc=new HashSet<>(flChange);  //去重
        flChange.clear();
        flChange.addAll(fc);
        return s;  //返回本次执行的类型以及处理的文件
    }


    //有序变化，每次变化 times 条，文件和类型都固定
    public ArrayList<String> forwardChangeTestChangeInOrder(String fileName,String type,Integer times){
      ArrayList<String> s=new ArrayList<>();

        if(type.equals("insert")) {
            insertFwdTimes(fileName,times);
            s.add(fileName);
            s.add(type);
        }else{
            if(type.equals("changePort")){
                changeFwdPortTimes(fileName,times);
                s.add(fileName);
                s.add(type);
            }else
            {
                if(nextDel.size()==nextChangePort.size()&&type.equals("del")) {
                    delFwdTimes(fileName,times/100);
                    s.add(fileName);
                    s.add(type);
                }
            }
        }
        HashSet<fibLine> fc=new HashSet<>(flChange);  //去重
        flChange.clear();
        flChange.addAll(fc);
        return s;  //返回本次执行的类型以及处理的文件
    }

    public void insertOne(String fileName){
        //非首次
        readForwardFile(OUTPUT_PATH, "insert");  //读取insert

       // fileName="chic";
        int j=0;
       switch (fileName){
           case "newy32aoa":
               j=0;
               break;
           case "chic":
               j=1;
               break;
           case "kans":
               j=2;
               break;
           case "losa":
               j=3;
               break;
           case "hous":
               j=4;
               break;
           case "salt":
               j=5;
               break;
           case "atla":
               j=6;
               break;
           default:
               System.out.println("file Name error");
       }
        nextInsert.remove(fileName);

        flChange.clear();

        flChange.add(fl.get(j));

        fl.clear();

        readForwardFile(OUTPUT_PATH, fileName, change);   //读取改变前的Change

        fl.addAll(flChange);
        writeInTxt(fl,fileName,change);
    }

    //读取Rest文件于fl，随机取 times 行写入Change文件中，同时在Rest文件中删除相应的 times 行
    public void insertFwdOne(String fileName) {
        //非首次
        if (fileName != null) {
            readForwardFile(OUTPUT_PATH, fileName, rest);  //读取rest
        }
        if(fl.size()==0){
            return;
        }
        if(fl.size()==1){
            nextInsert.remove(fileName);
        }
        flChange.clear();

        int j = getRandom(0,fl.size() - 1);
        flChange.add(fl.get(j));
        fl.remove(j);

        writeInTxt(fl,fileName,rest);    //删除后写入rest,确保不重复插入
        fl.clear();


        readForwardFile(OUTPUT_PATH, fileName, change);   //读取改变前的Change
        writeInTxt(fl,fileName,preChange);                //记录改变前的Change

        fl.addAll(flChange);
       // flChange.clear();
        writeInTxt(fl,fileName,change);
    }


    //有序，读取Rest文件于fl，有序取 times 行写入Change文件中，同时在Rest文件中删除相应的 times 行，顺序执行而用
    public void insertFwdTimes(String fileName,Integer times) {
        //非首次
        if (fileName != null) {
            readForwardFile(OUTPUT_PATH, fileName, rest);  //读取rest
        }

        if(fl.size()<=times){
            times=fl.size();
            nextInsert.remove(fileName);
        }
        flChange.clear();
        ArrayList<fibLine> ofl=new ArrayList<>(fl);
        for(fibLine f:ofl){
            flChange.add(f);
            fl.remove(f);
            if(flChange.size()==times) {
                break;
            }
        }

        writeInTxt(fl,fileName,rest);    //删除后写入rest,确保不重复插入
        fl.clear();


        readForwardFile(OUTPUT_PATH, fileName, change);   //读取改变前的Change
        writeInTxt(fl,fileName,preChange);                //记录改变前的Change

        fl.addAll(flChange);
        //flChange.clear();
        writeInTxt(fl,fileName,change);
    }


    //随机更改某一条的 action 从A到B
    public void changeFwdPortOne(String fileName) {

        if (fileName != null) {
            readForwardFile(OUTPUT_PATH, fileName, change);  //读取change
        }
        writeInTxt(fl, fileName, preChange);                //记录改变前的Change
        flChange.clear();
        while (true) {
            int p = getRandom(1, fl.size() - 1);  //p处的action换成和q处的action一样，保证第一条不被改变
            int q = getRandom(1, fl.size() - 1);
            if (!fl.get(p).port.equals(fl.get(q).port)) {
                flChange.add(fl.get(p)); //旧
                flChange.add(fl.get(q)); //新
                fl.get(p).port = fl.get(q).port;
                break;
            }
        }
        writeInTxt(fl, fileName, change);            //重新写入
    }

    //有序，times行变化，为顺序执行而设置
    public void changeFwdPortTimes(String fileName,Integer times) {
        if (fileName != null) {
            readForwardFile(OUTPUT_PATH, fileName, change);  //读取change
        }
        writeInTxt(fl, fileName, preChange);                //记录改变前的Change

        if(fl.size()<=times){
            times=fl.size();
        }
        flChange.clear();
        int k=portTime%fl.size();
        if(k==0){
            k=1;
            portTime++;
        }
        String po=fl.get(k).port;
       for(int i=k;i<(portTime+times)%fl.size();i++) {
           if(!fl.get(i).port.equals(fl.get(i+1).port)){
               flChange.add(fl.get(i));
               flChange.add(fl.get(i+1));
               fl.get(i).port = fl.get(i+1).port;   //第一条的action改为下一条的action，可能port未改变
           }
       }
        if(!fl.get((portTime+times)%fl.size()).port.equals(po)){
            flChange.add(fl.get((portTime+times)%fl.size()));
            flChange.add(fl.get(k));
            fl.get((portTime+times)%fl.size()).port = po;
        }

        writeInTxt(fl, fileName, change);      //重新写入
    }


    //每次随机删除一个
    public void delFwdOne(String fileName){
        if(fileName != null){
            readForwardFile(OUTPUT_PATH,fileName,change);  //读取change
        }
        writeInTxt(fl,fileName,preChange);                 //记录改变前的Change

        if(fl.size()==1){
            System.out.println(fileName+" 本次已经全部删除，运行结束");
            nextDel.remove(fileName);
            return; //不删除第一条
        }
        flChange.clear();

        int j=1;

        if(fl.size()>2){
            j = getRandom(1,fl.size() - 1);  //不删除第一条
        }
        flChange.add(fl.get(j));
        fl.remove(j);

        writeInTxt(fl,fileName,change);   //重新写回
   }

   //有序删除times个
    public void delFwdTimes(String fileName,Integer times){
        if(fileName != null){
            readForwardFile(OUTPUT_PATH,fileName,change);  //读取change
        }
        writeInTxt(fl,fileName,preChange);                //记录改变前的Change

        flChange.clear();
        if(fl.size()<=times){
            System.out.println(fileName+" 本次已经全部删除，运行结束");
            nextDel.remove(fileName);
            for(fibLine i:fl){
                if(!i.port.equals("drop")) {  //第一条不删除
                    flChange.add(i);
                    fl.remove(i);
                }
            }

        }else {
            ArrayList<fibLine> ofl=new ArrayList<>(fl);
            for(fibLine fb:ofl){
                if(!fb.port.equals("drop")) {  //第一条不删除
                    flChange.add(fb);
                    fl.remove(fb);
                    times--;
                }
                 if(times==0) {
                     break;
                 }
            }
        }

        writeInTxt(fl,fileName,change);   //重新写回
    }

    //带随机种子
    public int getRandom(int end){
        java.util.Random r=new java.util.Random(seed.get(seed.size()-1));
        return r.nextInt(end);
    }

    //[star,end]
    public int getRandom(int start,int end){
        return (int) (Math.random() * (end-start+1)) + start;
    }

    //读取文件于列表
    public void readForwardFile(String filePkg,String fwdDeviceName){
        try {
            File file = new File(filePkg+fwdDeviceName);
            if(file.isFile() && file.exists()) {
                InputStreamReader isr = new InputStreamReader(new FileInputStream(file), "utf-8");
                BufferedReader br = new BufferedReader(isr);
                String lineTxt = null;
                String[] s;
                fl.clear();
                while ((lineTxt = br.readLine()) != null) {
                    s=lineTxt.split(" ");
                    if(s.length==4&&s[0].equals("fw")) {
                        fibLine f = new fibLine(s[0], s[1], s[2], s[3]);
                        fl.add(f);
                    }
                }
                br.close();
            } else {
                System.out.println("文件不存在!");
            }
        } catch (Exception e) {
            System.out.println("文件读取错误!");
        }
    }


    public void readForwardFile(String filePkg,String fwdDeviceName,String tail){
        try {
            File file = new File(filePkg+fwdDeviceName+tail);
            if(file.isFile() && file.exists()) {
                InputStreamReader isr = new InputStreamReader(new FileInputStream(file), "utf-8");
                BufferedReader br = new BufferedReader(isr);
                String lineTxt = null;
                String[] s;
                fl.clear();
                while ((lineTxt = br.readLine()) != null) {
                    s=lineTxt.split(" ");
                    fibLine f=new fibLine(s[0],s[1],s[2],s[3]);
                    fl.add(f);
                }
                br.close();
            } else {
                System.out.println("文件不存在!");
            }
        } catch (Exception e) {
            System.out.println("文件读取错误!");
        }
    }

    public void writeInTxt(ArrayList<fibLine> fwd,String fileName,String tail){
        try {
            File file = new File(OUTPUT_PATH + fileName + tail);
            if (file.exists()) {
                file.delete();
            }
            PrintWriter pw = new PrintWriter(new BufferedWriter(new FileWriter(OUTPUT_PATH + fileName + tail)));
            for (fibLine f : fwd) {
                pw.println(f.ruleType + " " + f.predicate + " " + f.preLength + " " + f.port);
            }
            pw.close();
        }catch (Exception e) {
            System.out.println("文件写入错误!");
        }
    }


    //初始划分
    //i2--初始工作--产生i2Test
    public void fwdChangeI2(String fwdDeviceName,double m,Boolean hasSort){  //首次  -- 运算完成
        String path = "config/i2/";  //首次
        if(fwdDeviceName != null){
            readForwardFile(path,fwdDeviceName);
        }
        length=fl.size();
        if(hasSort){
            firstTimeHasSort(fwdDeviceName,m);
        }else
        {
            firstTimeNoSort(fwdDeviceName,m);
        }

    }

    public void firstTimeHasSort(String fileName,double m){
        if(m>1){
            m=1;
            System.out.println("m超过100%，现在取100%");
        }
        flNotAll.clear();
        flRest.clear();
        //--------------------------------  排序+不随机 -------------------------------------
        //排序
        fibLine fb=new fibLine();
        for(int i=0;i<fl.size()-1;i++){
            for(int j=i+1;j<fl.size();j++){
                if((Integer.parseInt(fl.get(i).preLength))>(Integer.parseInt((fl.get(j).preLength)))){
                    fb=fl.get(i);
                    fl.get(i).port=fl.get(j).port;
                    fl.get(i).preLength=fl.get(j).preLength;
                    fl.get(i).predicate=fl.get(j).predicate;
                    fl.get(i).ruleType=fl.get(j).ruleType;
                    fl.get(j).port=fb.port;
                    fl.get(j).preLength=fb.preLength;
                    fl.get(j).predicate=fb.predicate;
                    fl.get(j).ruleType=fb.ruleType;
                }
            }
        }
        //按长度顺序插入，不随机
        if(m==0){
            for (fibLine f : fl) {
                if (flNotAll.size() < 1) {
                    flNotAll.add(f);
                } else {
                    flRest.add(f);
                }
            }
        }else {
            for (fibLine f : fl) {
                if (flNotAll.size() < fl.size() * m) {
                    flNotAll.add(f);
                } else {
                    flRest.add(f);
                }
            }
        }

        writeInTxt(flNotAll,fileName,"Change"); //   0-2/3
        writeInTxt(flNotAll,fileName,"changePre");
        writeInTxt(flRest,fileName,"Rest"); // 2/3-1
    }

    public void firstTimeNoSort(String fileName,double m){
        if(m>1){
            m=1;
            System.out.println("m超过100%，现在取100%");
        }
        flNotAll.clear();

       fibLine fb=new fibLine();
        //---------------------------------随机选取+不排序-------------------------------
        fb=fl.get(0);
        flNotAll.add(fb);   //保证第一条被插入
        fl.remove(fb);

        int length=fl.size();
        for(int j=0;j<(int)(length*m);j++) {
            int i = getRandom(0,fl.size() - 1);
            fb=fl.get(i);
            flNotAll.add(fb);
            fl.remove(fb);
        }


        writeInTxt(flNotAll,fileName,"Change"); //   0-2/3
        writeInTxt(flNotAll,fileName,"changePre");
        writeInTxt(fl,fileName,"Rest"); // 2/3-1
    }



    public void fwdChangeI2(String fwdDeviceName,double m){  //首次  -- 有序运算完成
        String path = "config/i2/";  //首次
        if(fwdDeviceName != null){
            readForwardFile(path,fwdDeviceName);
        }
        firstTimeChangeInOder(fwdDeviceName,m);
    }


    public void firstTimeChangeInOder(String fileName,double m){
        if(m>1){
            m=1;
            System.out.println("m超过100%，现在取100%");
        }
        flNotAll.clear();
        flRest.clear();

        if(m==0){
            for (fibLine f : fl) {
                if (flNotAll.size() < 1) {
                    flNotAll.add(f);
                } else {
                    flRest.add(f);
                }
            }
        }else {
            for (fibLine f : fl) {
                if (flNotAll.size() < fl.size() * m) {
                    flNotAll.add(f);
                } else {
                    flRest.add(f);
                }
            }
        }
        writeInTxt(flNotAll,fileName,"Change");
        writeInTxt(flNotAll,fileName,"changePre");
        writeInTxt(flRest,fileName,"Rest");
    }

    public static class fibLine{
        String ruleType;
        String predicate;
        String preLength;
        String port;
        public fibLine(){

        }
        public fibLine(String ruleType,String predicate,String preLength,String port){
            this.ruleType=ruleType;
            this.predicate=predicate;
            this.preLength=preLength;
            this.port=port;
        }
    }


}
